/*******************************************************************************************
 *
 *   raylib [shapes] example - Cubic-bezier lines
 *
 *   Example originally created with raylib 1.7, last time updated with raylib 1.7
 *
 *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
 *   BSD-like license that allows static linking with closed source software
 *
 *   Copyright (c) 2017-2022 Ramon Santamaria (@raysan5)
 *
 ********************************************************************************************/
#include <stdio.h>
#include "raylib.h"
#include "pub_lib.h"

Vector2 control_points[4];
int point_cnt = 0;

int divisions = 1000;

/* if point number is 4, return 1
 * return 0 otherwise */
int update_points(Vector2* v, int* cnt)
{
	int draw_curve = 0;
	if(*cnt >= 4)
		return 1;//keep drawing previous curve

	control_points[*cnt] = GetMousePosition();
	printf("Left button of the mouse is clicked - position (%d %d)\n",
		(int)control_points[*cnt].x, (int)control_points[*cnt].y);
	(*cnt)++;
	if( *cnt >= 4) {
		draw_curve = 1;
		printf("\n");
	}

	return draw_curve;
}

#define POINTS_LIMITS 100
Vector2 points_array[POINTS_LIMITS];
int stack_top = 0;

Vector2 recursive_bezier(Vector2* v, float t, int order)
{
	Vector2 *head;

	if (order == 0) {
		return points_array[stack_top - 1];
	}

	head = &points_array[stack_top];
	for (int i = 0; i < order; i++) {
		points_array[stack_top] = Vector2Lerp(v[i], v[i+1], t);
		stack_top++;
	}
	return recursive_bezier(head, t, order - 1);
}

// TODO: Iterate through all t = 0 to t = 1 with small steps, and
// call de Casteljau's recursive Bezier algorithm.
void DrawBezier(Vector2* v, int order)
{
	float step = 1.0f / divisions;
	float t = 0.0f;
	Vector2 p;

	for (int i = 0; i <= divisions; i++){
		t = step * i;
		stack_top = 0; //reset stack
		p = recursive_bezier(v, t, order);
		DrawPixelV(p, GREEN);
	}
}

//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
	// Initialization
	//--------------------------------------------------------------------------------------
	const int screenWidth = 700;
	const int screenHeight = 700;
	char key;
	int draw = 0, i;
	Vector2* pv;

	SetConfigFlags(FLAG_MSAA_4X_HINT);
	InitWindow(screenWidth, screenHeight, "Bezier Curve");

	SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
	//--------------------------------------------------------------------------------------

	// Main game loop
	while (!WindowShouldClose())    // Detect window close button or ESC key
	{
		key = (char)GetKeyPressed();
		if (key == ESC_KEY) {
			break;
		} else if (key == 'C') {
			//clear points
			draw = 0;
			point_cnt = 0;
		}

		// Update
		//----------------------------------------------------------------------------------
		if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) {
			draw = update_points(control_points, &point_cnt);
		}
		//----------------------------------------------------------------------------------

		// Draw
		//----------------------------------------------------------------------------------
		BeginDrawing();

		ClearBackground(BLACK);

		pv = control_points;
		for(i = 0; i < point_cnt; i++, pv++) {
			DrawCircle((int)pv->x, (int)pv->y, 3.0f, WHITE);
		}

		if (draw) {
			DrawLineBezierCubic(control_points[0], control_points[3],
				control_points[1], control_points[2], 2.0f, RED);
			DrawBezier(control_points, point_cnt - 1);
		}

		EndDrawing();
		//----------------------------------------------------------------------------------
	}

	// De-Initialization
	//--------------------------------------------------------------------------------------
	CloseWindow();        // Close window and OpenGL context
	//--------------------------------------------------------------------------------------

	return 0;
}
